package niu.toy.spring.mvc.impl;


import lombok.Data;

import niu.toy.spring.mvc.*;
import niu.toy.spring.support.impl.ParameterNameDiscovererComposite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * action执行器
 */
@Data
public class RequestHandlerExecutor implements HandlerExecutor {
    private static final Logger logger = LoggerFactory.getLogger(RequestHandlerExecutor.class);
    
    private ArgumentResolverComposite argumentResolvers=new ArgumentResolverComposite();
    private HandlerReturnValueComposite returnValueHandlers=new HandlerReturnValueComposite();
    //handler参数名发现
    private ParameterNameDiscovererComposite  parameterNameDiscoverer=new ParameterNameDiscovererComposite();

    @Override
    public boolean supports(Object handler) {
        return true;
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        ServletWebRequest webRequest = new ServletWebRequest(request, response);
        try {
            HandlerWrapper handlerWrapper = new HandlerWrapper( (HandlerMethod) handler);
            handlerWrapper.setArgumentResolvers(this.argumentResolvers);
            handlerWrapper.setParameterNameDiscoverer(this.parameterNameDiscoverer );

            ModelAndViewContainer mavContainer=new ModelAndViewContainer();
            Object returnValue=handlerWrapper.invokeHandler(webRequest,mavContainer);
            try {
                HandlerMethodParameter returnType=( (HandlerMethod) handler).getReturnValueType(returnValue);
                this.returnValueHandlers.handleReturnValue(returnValue,returnType, mavContainer, webRequest);
            }
            catch (Exception ex) {
                throw ex;
            }
            return getModelAndView(mavContainer, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }

    private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {

        if (mavContainer.isRequestHandled()) {
            return null;
        }
        Map<String, Object> model = mavContainer.getModel();
        ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
        mav.setStatus(mav.getStatus());
        if (!mavContainer.isViewReference()) {
            mav.setView((View) mavContainer.getView());
        }
        return mav;
    }


}
